extern "C" {
#include "peripheral_api.h"
}
#include<fcntl.h>
#include<unistd.h>
#include<cstring>
#include<cstdio>
#include<memory>

#include<atlas_utils.h>
#include <dvpp_process.h>
#include <atlas_type.h>

/**
 * There a macro |#define|d in atlas_utils.h
 * #define ALIGN_UP(num, align) (((num) + (align) - 1) & ~((align) - 1))
 */

#define BUF_SIZE (352*288*3+1024)
const uint32_t WIDTH  = 352;
const uint32_t HEIGHT = 288;
uint8_t buf[BUF_SIZE];


bool check_cam_ret(int ret) {
  if(ret==LIBMEDIA_STATUS_OK) {
    perror("Looks good!");
    return true;
  }
  else {
    perror("Bad.");
    return false;
  }
}

bool check_acl_ret(int ret) {
  if(ret != 0) {
    perror("ACL error");
    _exit(-1);
  }
  else {
    perror("Success");
  }
  return true;
}

void activateCamera(int camId) {
  enum CameraProperties prop = CAMERA_PROP_CAP_MODE;
  enum CameraCapMode mode = CAMERA_CAP_ACTIVE;
  int ret;
  ret = SetCameraProperty(camId, prop, (void*)&mode);
  check_cam_ret(ret);
  if(ret) {
    printf("-------------\n");
  }
  return;
}

void readOneFrame(const int camId, void *pdata, int *size, const char *outFile) {
  int ret = ReadFrameFromCamera(camId, pdata, size);
  printf("buffersize: %d\n", *size);
  if(check_cam_ret(ret)) {
    printf("I've fetched some data from camera!\n");
    printf("Let's have it written to a file: ");
    printf("%s\n", outFile);
    int fd = open(outFile, O_WRONLY|O_CREAT, 644);
    if(fd<0) {
      perror("Could not open file");
    }
    write(fd, pdata, *size);
    close(fd);
  }
}

void inflateImage(ImageData &im) {
  im.format = PIXEL_FORMAT_YUV_SEMI_PLANNER_420_10BIT;
  im.height =  HEIGHT;
  im.width  = WIDTH;
  im.alignHeight = ALIGN_UP16(im.height);
  im.alignWidth  = ALIGN_UP128(im.width);
  im.size = BUF_SIZE;
  im.data = std::make_shared<uint8_t>(BUF_SIZE);
}

int main() {
  int ret = aclInit(NULL);
  check_acl_ret(ret);
  MediaLibInit();
  int bufSize = BUF_SIZE;
  int cameraIds[2] = {0, 0};
  uint32_t cnt = 2;
  ret = QueryCameraIds(cameraIds, &cnt);
  if(check_cam_ret(ret)) {
    printf("There are %d camera(s) available\n", cnt);
    for(int i=0; i<2; ++i) {
      printf("Camera %d: %d\n", i, cameraIds[i]);
    }
  }
  ret = OpenCamera(cameraIds[0]);
  if(check_cam_ret(ret)) {
    printf("OPEN CAMERA\n");
  }

  struct CameraResolution resolution;
  resolution.height = 288;
  resolution.width = 352;
  ret = SetCameraProperty(0, CAMERA_PROP_RESOLUTION, &resolution);
  if(LIBMEDIA_STATUS_OK != ret) {
      printf("SetCameraProperty 0 failed %d\r\n", ret);
      return -1;
  }

  activateCamera(cameraIds[0]);

  DvppProcess dvpp_process;
  dvpp_process.Init();
  ImageData src, dest;
  // inflateImage(src); inflateImage(dest);
  dest.format = PIXEL_FORMAT_RGB_888;

  memset(buf, 0, sizeof(buf));

  const char *outFileNames[] = {"image1", "image2"};
  for(int i=0; i<2; ++i)
    readOneFrame(cameraIds[0], buf, &bufSize, outFileNames[i]);
  // It's checked that the |md5sum| of the two images are different

  ret = CloseCamera(cameraIds[0]);
  if(check_cam_ret(ret)) {
    printf("...And close it.\n");
  }

  // src.data.reset(buf);
  // dvpp_process.JpegE(dest, src);
  // Finalize
  ret = aclFinalize();
  if(ret == 0) {
    printf("Success!\n");
  }
  return 0;
}
